package ch.unisi.inf.pfii.teamwhite.risk.core;

/**
 * 
 * @author Matteo Bellan: bellanm@lu.unisi.ch
 * @author Andrea Michelotti: micheloa@lu.unisi.ch
 * @author Ranganathan Ramasubramanian: ramasubr@lu.unisi.ch
 *
 */

import java.util.ArrayList;

import ch.unisi.inf.pfii.teamwhite.risk.buildings.EldestCouncil;
import ch.unisi.inf.pfii.teamwhite.risk.buildings.SlaveryCamp;
import ch.unisi.inf.pfii.teamwhite.risk.buildings.TaxCenter;
import ch.unisi.inf.pfii.teamwhite.risk.core.io.MapReader;
import ch.unisi.inf.pfii.teamwhite.risk.core.player.Ai;
import ch.unisi.inf.pfii.teamwhite.risk.core.player.Human;
import ch.unisi.inf.pfii.teamwhite.risk.core.player.Player;

public final class Game {
	
	private Galaxy galaxy;
	
	private ArrayList<Player> players;
	private int numberOfPlayers;
	private Player currentPlayer;
	private int playerPointer;
	
	private MapReader mapReader;
	private String mapName;
	
	private final ArrayList<GameListener> listeners;

//  This constructor initialize the game and creates players and listeners
	public Game() {
		this.players = new ArrayList<Player>();
		numberOfPlayers = 2;
		listeners = new ArrayList<GameListener>();
		mapReader = new MapReader();
	}

//	Getters and setters 
	public Galaxy getGalaxy() {
		return galaxy;
	}
	
	public ArrayList<Player> getPlayers() {
		return players;
	}

	private final void setNumberOfPlayers(final int number) {
		numberOfPlayers = number;
	}
	
	public Player getCurrentPlayer() {
		return currentPlayer;
	}
	
	public void addGameListener(final GameListener li){
		listeners.add(li);
	}
	
	public void removeGameListener(final GameListener li){
		listeners.remove(li);
	}
	
//	Fires methods
	private void firePlayerLoose(final Player player){
		for (final GameListener li : listeners) {
			li.playerLoose(player);
		}
	}
	
	private void firePlayerWon(final Player player){
		for (final GameListener li : listeners) {
			li.playerWon(player);
		}
	}
	
//	This method sets the players and creates the galaxy
	public final void initialSetter(final Player player, final String mapName){
		currentPlayer = player;
		galaxy = new Galaxy(mapName);
		this.mapName = mapName;
	}
	
//	This method set a new player and adds it to the list of players
	public final void setPlayer(final String name, final String type) {
		Player player = null;
		if (type.equals("Ai")) {
			player = new Ai(name);
		} else {
			player = new Human(name);
		}
		players.add(player);
		player.setColor(getPlayerColor(players.indexOf(player)));
		setNumberOfPlayers(players.size());
	}
	
//	This method set the color of all the players.
	private final String getPlayerColor(final int index) {
		String result = "";
		switch (index) {
		case 0:
			result = "BLUE";
			break;
		case 1:
			result = "RED";
			break;
		case 2:
			result = "GREEN";
			break;
		case 3:
			result = "YELLOW";
			break;
		case 4:
			result = "CYAN";
			break;
		case 5:
			result = "MAGENTA";
			break;
		case 6:
			result = "GRAY";
			break;
		case 7:
			result = "ORANGE";
		}
		return result;
	}
	
//	TODO
//	This method checks if there is a condition of victory or defeat
	public final void checkPlayerState() {
		for (int i = 0 ; i < players.size(); i++) {
			if (players.get(i).getTerritory().size() == 0 && !players.get(i).isDuringAssignment()) {
				if (playerPointer + 1 == players.size()) {
					playerPointer--;
				}
				firePlayerLoose(players.get(i));
				numberOfPlayers--;
				players.remove(players.get(i));
				nextPlayer();
			}
			if (players.size() == 1 && !players.get(0).isDuringAssignment()) {
				firePlayerWon(players.get(0));
			}
		}
	}

//	This method sets the current player to the next one.
	public final void nextPlayer() {
		if (playerPointer + 1 == numberOfPlayers) {
			playerPointer = 0;
			currentPlayer = players.get(playerPointer);
		} else {
			playerPointer++;
			currentPlayer = players.get(playerPointer);
		}
		updatePlayerMoney(currentPlayer);
		checkRegions(currentPlayer, mapReader.getRegions(mapName));
	}

//	This method updates, at the begin of each turn, the amount of the profit of a player.
	private final void updatePlayerMoney(final Player currentPlayer) {
		int profit = 0;
		int capitals = 0;
		int capitalsBonus = 1000;
		for (Planet planet : currentPlayer.getTerritory()) {
			if (planet.getBuilding().getName().equals("Slavery Camp")) {
				SlaveryCamp building = (SlaveryCamp) planet.getBuilding();
				building.slavery(planet);
			} else if (planet.getBuilding().getName().equals("Tax Center")) {
				TaxCenter building = (TaxCenter) planet.getBuilding();
				profit = profit + planet.getMoney() + building.extraIncome(planet.getNeighbours());
			} else if (planet.getBuilding().getName().equals("Eldest Council")) {
				EldestCouncil building = (EldestCouncil) planet.getBuilding();
				profit = profit + planet.getMoney() + building.bonus(planet.getNeighbours(), planet);
				capitals++;
			} else {
				profit = profit + planet.getMoney();
			}
		}
		if (capitals == numberOfPlayers) {
			capitalsBonus = 2000;
		}
		currentPlayer.setMoney((capitals * capitalsBonus) + (currentPlayer.getMoney() + profit));
	}
	
//	This method checks if a player controls an entire region and in this case, gives him a bonus
	private final void checkRegions(final Player currentPlayer, final ArrayList<String[]> regions) {
		int region0 = 0;
		int region1 = 0;
		int region2 = 0;
		int region3 = 0;
		int region4 = 0;
		for (Planet planet : currentPlayer.getTerritory()) {
			if (planet.getRegion().equals(regions.get(0)[1])) {
				region0++;
			} else if (planet.getRegion().equals(regions.get(1)[1])) {
				region1++;
			} else if (planet.getRegion().equals(regions.get(2)[1])) {
				region2++;
			} else if (planet.getRegion().equals(regions.get(3)[1])) {
				region3++;
			} else if (planet.getRegion().equals(regions.get(4)[1])) {
				region4++;
			}
		}
		if (region0 == Integer.parseInt(regions.get(0)[2])) {
			currentPlayer.setMoney(currentPlayer.getMoney() + Integer.parseInt(regions.get(0)[3]));
		} else if (region1 == Integer.parseInt(regions.get(1)[2])) {
			currentPlayer.setMoney(currentPlayer.getMoney() + Integer.parseInt(regions.get(1)[3]));
		} else if (region2 == Integer.parseInt(regions.get(2)[2])) {
			currentPlayer.setMoney(currentPlayer.getMoney() + Integer.parseInt(regions.get(2)[3]));
		} else if (region3 == Integer.parseInt(regions.get(3)[2])) {
			currentPlayer.setMoney(currentPlayer.getMoney() + Integer.parseInt(regions.get(3)[3]));
		} else if (region4 == Integer.parseInt(regions.get(4)[2])) {
			currentPlayer.setMoney(currentPlayer.getMoney() + Integer.parseInt(regions.get(4)[3]));
		}
	}	
}